package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.deer.wms.base.system.dao.ErpBackRecordMapper;
import com.deer.wms.base.system.model.Area.AreaInfo;
import com.deer.wms.base.system.service.AreaInfoService;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.inventory.constant.InventoryConstant;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.model.Inventory.InventoryTransact;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.inventory.service.InventoryTransactService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.BeanUtils;
import com.deer.wms.project.root.util.Excel;
import com.deer.wms.project.root.util.StringUtils;
import com.deer.wms.system.manage.model.user.UserInfo;
import com.deer.wms.system.manage.service.CodeRuleService;
import com.deer.wms.system.manage.service.CrmDeptAreaService;
import com.deer.wms.ware.task.config.StrategyErpService;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.WaveDetailMapper;
import com.deer.wms.ware.task.model.SO.SoDetail;
import com.deer.wms.ware.task.model.SO.SoMaster;
import com.deer.wms.ware.task.model.Wave.WaveDetail;
import com.deer.wms.ware.task.model.Wave.WaveDetailCriteria;
import com.deer.wms.ware.task.model.Wave.WaveDetailDto;
import com.deer.wms.ware.task.model.Wave.WaveMaster;
import com.deer.wms.ware.task.model.out.OutDetail;
import com.deer.wms.ware.task.model.pickTask.PickTask;
import com.deer.wms.ware.task.service.*;

import com.deer.wms.ware.task.strategy.SoDetailStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

import java.util.stream.Collectors;

import static com.deer.wms.project.root.util.CollectionUtils.convertMap;

/**
 * @author wei
 * @date 2020/02/02
 */
@Service
@Transactional

public class WaveDetailServiceImpl extends SuperServiceImpl<WaveDetailMapper, WaveDetail> implements WaveDetailService {

    @Autowired
    private WaveDetailMapper waveDetailMapper;
    @Autowired
    private WaveDetailServiceImpl waveDetailService;
    @Autowired
    private SoMasterServiceImpl soMasterService;
    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private SoDetailService soDetailService;
    @Autowired
    private InventoryTransactService inventoryTransactService;
    @Autowired
    private ErpBackRecordMapper erpBackRecordMapper;
    @Autowired
    private OutMasterService outMasterService;

    @Autowired
    private PushErpService pushErpService;
    @Autowired
    private CellInfoService cellInfoService;

    @Autowired
    private AsyncService asyncService;
    @Autowired
    private StrategyErpService strategyErpService;
    @Autowired
    private CodeRuleService codeRuleService;

    @Autowired
    private CrmDeptAreaService crmDeptAreaService;

    @Value("${wave.direct}")
    //直发虚仓
    private Integer directId;
    @Value("${wave.vmi}")
    //VMI仓库id
    private Integer vmiId;

    @Value("${wave.start}")
    //先發配件
    private Integer start;


    @Override
    public List<WaveDetailDto> findList(WaveDetailCriteria criteria) {

        return waveDetailMapper.findList(criteria);

    }

    @Override
    public List<WaveDetail> getByMasterId(Integer waveId) {
        return waveDetailMapper.getByMasterId(waveId);
    }

    @Override
    public void deleteByWaveMasterId(Integer id) {

        WaveDetailCriteria criteria = new WaveDetailCriteria();
        criteria.setWaveId(id);
        waveDetailMapper.deleteByWaveMasterCode(criteria);
    }

    @Override
    public void suggestForPick(List<WaveDetail> detailList, UserInfo wareUser, CurrentUser currentUser) {
        //波次明细 关联 仓库员
//        List<WaveDetail> list = new ArrayList<>();
        for (WaveDetail waveDetail : detailList) {
            //波次明细绑定仓管员。  后续拣货是按仓管员分组进行操作
            //不能更换仓管员
            if (ObjectUtil.equals(WareTaskConstant.WAVE_STATE_PICKING, waveDetail.getState()) && ObjectUtil.notEqual(wareUser.getUserId(),
                    waveDetail.getPickUserId())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "部分推荐的波次明细不允许更换仓管员");
            }

        }

        //分配库存，调用公共方法。

        pickTaskService.createPickTask(detailList, wareUser);
    }


    private static final Logger log = LoggerFactory.getLogger(WaveDetailServiceImpl.class.getSimpleName());

    @Override
    public Map<String, String> sendOut(List<Integer> pickIds, CurrentUser currentUser) {

        List<PickTask> pickTasks = pickTaskService.listByIds(pickIds);
        //找到对应的库存
        List<Integer> invIdList = pickTasks.stream().map(PickTask::getInventoryId).collect(Collectors.toList());
        List<Inventory> inventories = inventoryService.listByIds(invIdList);

        double sum1 = inventories.stream().mapToDouble(Inventory::getQuantity).sum();
        Set<OutDetail> outDetailSet = new HashSet<>();
        Set<SoDetail> soDetailSet = new HashSet<>();
        //先按波次明细分组  ArrayDeque
        Map<String, List<Inventory>> map = inventories.stream().filter(item -> ObjectUtil.isNotEmpty(item.getBillNo())).collect(Collectors.groupingBy(Inventory::getBillNo));


        Set<String> waveDetailCodes = map.keySet();

        List<WaveDetail> waveDetails = waveDetailService.list(new QueryWrapper<WaveDetail>().in("wave_detail_code", waveDetailCodes));
        //波次明细转换
        Map<String, WaveDetail> waveDetailMap = convertMap(waveDetails, WaveDetail::getWaveDetailCode);
        //
        List<Integer> waveDetailLIds = waveDetailMap.values().stream().map(WaveDetail::getWaveDetailId).collect(Collectors.toList());
        List<SoDetail> soDetailList = soDetailService.list(new QueryWrapper<SoDetail>().in("wave_detail_id", waveDetailLIds));
        Map<Integer, List<SoDetail>> soDetailMap = soDetailList.stream().collect(Collectors.groupingBy(SoDetail::getWaveDetailId));

        for (String waveDetailCode : waveDetailCodes) {
//            WaveDetail waveDetail = waveDetailService.getOneByField("wave_detail_code", waveDetailCode);
            WaveDetail waveDetail = waveDetailMap.get(waveDetailCode);

            QueryWrapper<SoDetail> soDetailQw = new QueryWrapper<>();
            // //08.04.0389
            soDetailQw.eq("wave_detail_id", waveDetail.getWaveDetailId());
            List<SoDetail> soDetails = soDetailMap.get(waveDetail.getWaveDetailId());
            if (ObjectUtil.isEmpty(soDetails)) {
                continue;
            }
            ArrayDeque<SoDetail> ad = new ArrayDeque<>(soDetails);
            List<Inventory> allotInvs = map.get(waveDetailCode);
            //分配库存
            //多个库存对应一个波次明细   一个波次明细对应多个出库任务明细
            //  A1, A2, A3   ===>   B1
            //  B1  ===>  C1,C2,C3,C4,C5
            Set<OutDetail> extracted = extracted(ad, allotInvs, soDetailSet);
            outDetailSet.addAll(extracted);
        }


        double sum = outDetailSet.stream().mapToDouble(OutDetail::getDeliveryQuantity).sum();
        List<String> waveCode = pickTasks.stream().map(PickTask::getWaveCode).collect(Collectors.toList());

        List<SoMaster> soMasters = soMasterService.list(new QueryWrapper<SoMaster>().in("wave_code", waveCode));
        Set<String> collect3 = soMasters.stream().map(SoMaster::getBillNo).collect(Collectors.toSet());
        log.error("波次拣货出库数量:{}\t,回传数量:{}\t,任务单号:{}", sum1, sum, StringUtils.join(collect3, ","));
        //Step3.回写单据状态
        for (PickTask pickTask : pickTasks) {
            pickTask.setSeededQuantity(pickTask.getPickQuantity());
            pickTask.setState(WareTaskConstant.PICK_STATE_OUTED);
        }


        pickTaskService.updateBatchById(pickTasks);

        for (Inventory inventory : inventories) {
            waveDetailService.toStockRequest(inventory, currentUser);
            inventoryService.removeById(inventory);
        }

//        asyncService.asyncPushErp(inventories, collect1, currentUser);


//        throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "请录入 特采单号");

//        return returnMap;
        return null;
    }

    @Autowired
    private WaveMasterService waveMasterService;


    @Autowired
    private SoDetailStrategy soDetailStrategy;

    /**
     * 同步最新的数据（如皋需求，因为可能期间发生变化）
     *
     * @param waveCode 波次号
     */
    @Override
    public void syncCurrentData(String waveCode) {
        //1.整理数据，将明细行获取为一个set
        //2.将新旧soDetails 变为Map ，key为明细行
        List<SoDetail> allSoDetails = new ArrayList<>();
        List<SoMaster> soMasters = soMasterService.list(new QueryWrapper<SoMaster>().eq("wave_code", waveCode));
        List<SoDetail> newSoDetails = soDetailService.syncCurrentData(soMasters);
        List<WaveDetail> waveList = waveDetailService.list(new QueryWrapper<WaveDetail>().eq("wave_code", waveCode));
        Map<Integer, WaveDetail> waveDetailMap = convertMap(waveList, WaveDetail::getWaveDetailId);
        if (ObjectUtil.isEmpty(newSoDetails)) {
            newSoDetails = new ArrayList<>();
        }
        List<SoDetail> oldSoDetails = this.getSoDetailsByWaveCode(waveCode);
        if (ObjectUtil.isEmpty(oldSoDetails)) {
            newSoDetails = new ArrayList<>();
        }
        //对应波次详情
        //老单子新单子合并
        allSoDetails.addAll(oldSoDetails);
        allSoDetails.addAll(newSoDetails);

        //行号可能重复，不能作为唯一条件去重
        Map<SoDetail, SoDetail> newMap = newSoDetails.stream()
                .collect(Collectors.toMap(item -> item, soDetail -> soDetail, (oldValue, newValue) -> newValue));
        //新单子老单子合并
        Map<SoDetail, SoDetail> oldMap = oldSoDetails.stream()
                .collect(Collectors.toMap(item -> item, soDetail -> soDetail, (oldValue, newValue) -> newValue));
        //3.根据明细行去获取
        for (SoDetail key : allSoDetails) {
            SoDetail newSd = newMap.get(key);
            SoDetail oldSd = oldMap.get(key);
            WaveDetail oldWavedetail = new WaveDetail();
            oldWavedetail.setState(10);
            if (ObjectUtil.isNotEmpty(oldSd)) {
                oldWavedetail = waveDetailMap.get(oldSd.getWaveDetailId());
            }
            //数据对比
            soDetailStrategy.resolveSoDetail(oldSd, newSd, oldWavedetail, waveCode);
        }

        List<WaveDetail> waveDetails = waveDetailService.list(new QueryWrapper<WaveDetail>().eq("wave_code", waveCode));
        List<SoDetail> soDetails = getSoDetailsByWaveCode(waveCode);
        this.upState(waveDetails, soDetails);


    }


    public void upState(List<WaveDetail> waveDetails, List<SoDetail> soDetails) {

        for (WaveDetail waveDetail : waveDetails) {
            double allSum = soDetails.stream().filter(item -> item.getWaveDetailId().equals(waveDetail.getWaveDetailId())).mapToDouble(SoDetail::getAllottedQuantity).sum();
            waveDetail.setAllottedQuantity(allSum);
            if (allSum == 0) {
                waveDetail.setState(WareTaskConstant.WAVE_STATE_PROCESSING);
            } else if (ObjectUtil.equal(waveDetail.getQuantity(), waveDetail.getAllottedQuantity())) {
                waveDetail.setState(WareTaskConstant.WAVE_STATE_ALL_ALOT);
            } else if (ObjectUtil.equal(waveDetail.getQuantity(), waveDetail.getPickQuantity())) {
                waveDetail.setState(WareTaskConstant.WAVE_STATE_CLOSE);
            } else {
                waveDetail.setState(WareTaskConstant.WAVE_STATE_PICKING);
            }
        }
        waveDetailService.updateBatchById(waveDetails);

    }

    /**
     * 两个单子都有
     *
     * @param newSd
     * @param oldSd
     */

    public void updateOrderSo(SoDetail newSd, SoDetail oldSd) {
        //如果已经复核，回传给ERP则不需要改变
        if (oldSd.getOrderQuantity() - oldSd.getPickQuantity() == 0) {
            return;
        }
        //如果老单子删除
        soDetailService.removeById(oldSd.getSoDetailId());

        WaveDetail waveDetail = waveDetailService.getById(oldSd.getWaveDetailId());
        if (ObjectUtil.isEmpty(waveDetail)) {
            return;
        }

        //已分配
        if (waveDetail.getQuantity() > oldSd.getOrderQuantity()) {
            waveDetail.setQuantity(waveDetail.getQuantity() - oldSd.getOrderQuantity());
            waveDetailService.updateById(waveDetail);
        } else {
            waveDetailService.removeById(waveDetail);
        }


    }


    public Boolean isAdd(SoDetail soDetail, List<WaveDetail> list) {

        if (ObjectUtil.isEmpty(soDetail)) {
            return true;
        }
        Map<Integer, WaveDetail> waveDetailMap = convertMap(list, WaveDetail::getWaveDetailId);
        WaveDetail waveDetail = waveDetailMap.get(soDetail.getWaveDetailId());
        if (ObjectUtil.isEmpty(waveDetail)) {
            System.out.println("2");
            return true;
        }
        System.out.println(waveDetail.getWaveDetailId());
        if (waveDetail.getState() != 0) {
            System.out.println("1");
            return true;
        } else return false;

    }


    @Override
    public List<WaveDetailDto> updateXfQuantity(List<WaveDetailDto> waveDetails, Integer id) {
        WaveMaster waveMaster = waveMasterService.getById(id);
        List<Integer> areaIds = crmDeptAreaService.listByDeptId(waveMaster.getDeptId());

        if (ObjectUtil.isEmpty(waveDetails)) {
            return waveDetails;
        }
        Set<String> itemCodes = waveDetails.stream().map(WaveDetailDto::getItemCode).collect(Collectors.toSet());
        List<Inventory> inventories = inventoryService.list(new QueryWrapper<Inventory>().in("item_code", itemCodes));
        List<AreaInfo> areaInfos = areaInfoService.list(new QueryWrapper<AreaInfo>().in("wave_type", 3, 1, 2));


        for (WaveDetailDto waveDetail : waveDetails) {
            String itemCode = waveDetail.getItemCode();
            //可用库存
            waveDetail.setInvQty(this.invQty(inventories, areaIds, itemCode));
            //VMI库存
            waveDetail.setVmiQuantity(this.vmiQty(inventories, itemCode));
            //直发虚仓库存
            waveDetail.setZfQuantity(this.zfQuantity(inventories, itemCode));
            //先发配件库存
            waveDetail.setXfQuantity(this.xfQuantity(inventories, itemCode));
            //合格未入库库存
            waveDetail.setWarehouseQcQuantity(this.warehouseQcQuantity(inventories, itemCode));
            //所有库存
            waveDetail.setAllInQty(this.allInQty(inventories,itemCode, areaInfos));

        }
        return waveDetails;

    }

    @Autowired
    private AreaInfoService areaInfoService;

    public Double allInQty(List<Inventory> inventories, String itemCode, List<AreaInfo> areaInfos) {
        List<Integer> eprAreaIds = areaInfos.stream().map(item -> item.getErpAreaId()).collect(Collectors.toList());
        List<String> notCellCode = Arrays.asList("285000", "285333");
        return inventories.stream().filter(item ->
                        item.getItemCode().equals(itemCode)
                                //过滤合格未入库，待检
                                && !notCellCode.contains(item.getCellCode())
                                //不合格库，发出仓
                                && !eprAreaIds.contains(item.getErpAreaId())
                )
                .mapToDouble(menu -> menu.getQuantity() - menu.getAllotQuantity() - menu.getFreezeQuantity()).sum();
    }

    private Double warehouseQcQuantity(List<Inventory> inventories, String itemCode) {

        return inventories.stream().filter(item ->
                        item.getItemCode().equals(itemCode)
                                //过滤合格未入库，待检
                                && "285000".equals(item.getCellCode())
                )
                .mapToDouble(menu -> menu.getQuantity() - menu.getAllotQuantity() - menu.getFreezeQuantity()).sum();
    }

    /**
     * 可用库存
     *
     * @return
     */
    public Double invQty(List<Inventory> inventories, List<Integer> areaIds, String itemCode) {
        List<Integer> notAasnStock = pushErpService.getNotAasnStock();
        List<String> notCellCode = Arrays.asList("285000", "285333");
        double sum = inventories.stream().filter(item ->
                        item.getItemCode().equals(itemCode)
                                //数据权限
                                && areaIds.contains(item.getErpAreaId())
                                //过滤直发虚仓，先发配件，VMI
                                && !notAasnStock.contains(item.getAsnStockId())
                                //过滤合格未入库，待检
                                && !notCellCode.contains(item.getCellCode()))
                .mapToDouble(menu -> menu.getQuantity() - menu.getAllotQuantity() - menu.getFreezeQuantity()).sum();
        return sum;
    }




    /**
     * VMI库存
     *
     * @return
     */
    public Double vmiQty(List<Inventory> inventories,String itemCode) {
        List<String> notCellCode = Arrays.asList("285000", "285333");
        return inventories.stream().filter(item ->
                        item.getItemCode().equals(itemCode)
                                //过滤直发虚仓，先发配件，VMI
                                && vmiId.equals(item.getAsnStockId())
                                //过滤合格未入库，待检
                                && !notCellCode.contains(item.getCellCode()))
                .mapToDouble(menu -> menu.getQuantity() - menu.getAllotQuantity() - menu.getFreezeQuantity()).sum();



    }


    /**
     * 直发库存
     *
     * @return
     */
    public Double zfQuantity(List<Inventory> inventories,String itemCode) {
        List<String> notCellCode = Arrays.asList("285000", "285333");
        return inventories.stream().filter(item ->
                        item.getItemCode().equals(itemCode)
                                //过滤直发虚仓，先发配件，VMI
                                && directId.equals(item.getAsnStockId())
                                //过滤合格未入库，待检
                                && !notCellCode.contains(item.getCellCode()))
                .mapToDouble(menu -> menu.getQuantity() - menu.getAllotQuantity() - menu.getFreezeQuantity()).sum();
    }


    /**
     * 先发配件库存
     *
     * @return
     */
    public Double xfQuantity(List<Inventory> inventories,String itemCode) {
        List<String> notCellCode = Arrays.asList("285000", "285333");
        return inventories.stream().filter(item ->
                        item.getItemCode().equals(itemCode)
                                //先发库存
                                && start.equals(item.getErpAreaId())
                                //过滤合格未入库，待检
                                && !notCellCode.contains(item.getCellCode()))
                .mapToDouble(menu -> menu.getQuantity() - menu.getAllotQuantity() - menu.getFreezeQuantity()).sum();
    }



    /**
     * 修改状态跟数量
     *
     * @param waveDetail
     * @param vmiNumber
     */
    @Override
    public void updateState(WaveDetail waveDetail, Double vmiNumber) {
        waveDetail.setAllottedQuantity(waveDetail.getAllottedQuantity() + vmiNumber);
        updateById(waveDetail);
    }

    /**
     * 批量回传ERP
     */
    @Override
    public void sendWaveDetail() {
        pickTaskService.list(new QueryWrapper<PickTask>().eq("state", 0)
                .isNotNull("wave_code"));
    }

    /**
     * 修改任务单明细行跟状态
     *
     * @param waveMaster
     */
    @Override
//    @Async
    public void updateTotalSkuCount(WaveMaster waveMaster) {
        List<PickTask> pickTasks = pickTaskService.list(new QueryWrapper<PickTask>().eq("wave_code", waveMaster.getCode()));
        ;
        //计算任务单拣货回传行数
        List<PickTask> sendPick = pickTasks.stream().filter(item -> item.getState() == 5).collect(Collectors.toList());
        if (sendPick.size() == pickTasks.size()) {
            waveMaster.setState(WareTaskConstant.WAVE_STATE_PICKING);
        } else {
            //修改任务明细行
            waveMaster.setTotalSkuCount(pickTasks.stream().map(PickTask::getWaveDetailId).collect(Collectors.toSet()).size());
            waveMaster.setState(WareTaskConstant.WAVE_STATE_ALL_ALOT);
        }
        if (pickTasks.size() == 0) {
            waveMasterService.removeById(waveMaster);
        } else {
            waveMasterService.updateById(waveMaster);

        }

    }

    /**
     * 导出
     *
     * @param waveCode
     * @param httpServletResponse
     */
    @Override
    public void downLoad(String waveCode, HttpServletResponse response) {
        List<WaveDetail> waveDetails = list(new QueryWrapper<WaveDetail>().eq("wave_code", waveCode));
        Excel.outExcelFile(waveDetails, response, WaveDetail.class);
    }


    private List<SoDetail> getSoDetailsByWaveCode(String waveCode) {
        List<WaveDetail> waveDetails = waveDetailService.getListByField("wave_code", waveCode);
        Set<Integer> waveDetailIdsSet = waveDetails.stream()

                .map(waveDetail -> waveDetail.getWaveDetailId()).collect(Collectors.toSet());
        if (ObjectUtil.isEmpty(waveDetailIdsSet)) {
            return null;
        }
        return soDetailService.list(new QueryWrapper<SoDetail>().in("wave_detail_id", waveDetailIdsSet));
    }


    public void updateMaster(Set<OutDetail> outDetails) {
        //过滤单号
        Set<String> billSet = outDetails.stream().map(OutDetail::getBillNo).collect(Collectors.toSet());
        //通过单号查soMaster
        List<SoMaster> soMasterList = soMasterService.list(new QueryWrapper<SoMaster>().in("bill_no", billSet));
        //通过单号查SoDetail
        List<SoDetail> soDetailList = soDetailService.list(new QueryWrapper<SoDetail>().in("bill_no", billSet));
        //根据单号分组
        Map<String, List<SoDetail>> soDetailMap = soDetailList.stream().collect(Collectors.groupingBy(SoDetail::getBillNo));

        soMasterList.forEach(item -> {
            double deliverQty = soDetailMap.get(item.getBillNo()).stream().mapToDouble(SoDetail::getDeliveryQuantity).sum();
            item.setQcQty(item.getQcQty() + deliverQty);
        });
        soMasterService.updateBatchById(soMasterList);


//        Set<SoMaster> soMasterSet = new HashSet<>();
//        //根据订单号分组
//        Map<String, List<SoDetail>> detailMap = soDetails.stream().collect(Collectors.groupingBy(SoDetail::getBillNo));
//        //获取所有的订单号Key
//        Set<String> set = detailMap.keySet();
//        //获取出库单集合
//        List<SoMaster> soMasterList = soMasterService.list(new QueryWrapper<SoMaster>().in("bill_no", set));
//        Map<String, List<SoMaster>> soMasterMap = soMasterList.stream().collect(Collectors.groupingBy(SoMaster::getBillNo));
//        detailMap.forEach((key,val)->{
//            double deliverQty = detailMap.get(key).stream().mapToDouble(SoDetail::getDeliveryQuantity).sum();
//            //新增出库数量
//            SoMaster soMaster = soMasterMap.get(key).get(0);
//            soMaster.setQcQty(soMaster.getQcQty() + deliverQty);
//            soMasterSet.add(soMaster);
//        });
//        //批量修改
//        soMasterService.updateBatchById(soMasterSet);
    }

    /**
     * 分配数量，更新
     *
     * @param queue       SO 队列
     * @param allotInvs   待分配的库存
     * @param soDetailSet
     */
    private Set<OutDetail> extracted(ArrayDeque<SoDetail> queue, List<Inventory> allotInvs, Set<SoDetail> soDetailSet) {

        //08.04.0389    47667557
        double sum = allotInvs.stream().mapToDouble(Inventory::getQuantity).sum();
        double sum1 = queue.stream().mapToDouble(SoDetail::getOrderQuantity).sum();
        Set<OutDetail> outSet = new HashSet<>(queue.size());
        Set<SoDetail> set = new HashSet<>(queue.size());
//        List<OutDetail>
        for (Inventory allotInv : allotInvs) {
            Double invQty = allotInv.getQuantity();

            while (!queue.isEmpty()) {
                if (invQty <= 0) {
                    System.out.println("11111");
                    queue.poll();
                }
                if (ObjectUtil.isEmpty(queue)) {
                    continue;
                }
                OutDetail outDetail = new OutDetail();
                //取出队列的第一个元素
                SoDetail soDetail = queue.getFirst();

                //SO待填补的数量
                double soQty = soDetail.getOrderQuantity() - soDetail.getDeliveryQuantity();
                if (soQty == 0) {
                    queue.poll();
                    continue;
                }
                if (invQty < soQty) {
                    //库存不够分配，分配后直接跳出循环
                    soDetail.setDeliveryQuantity(soDetail.getDeliveryQuantity() + invQty);
                    soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_PART_SEND);
                    set.add(soDetail);
                    BeanUtils.copyProperties(soDetail, outDetail);
                    outDetail.setBoxCode(allotInv.getBoxCode());
                    outDetail.setCellCode(allotInv.getCellCode());
                    outDetail.setBatchName(allotInv.getBatchName());
                    outDetail.setErpAreaId(allotInv.getErpAreaId());
                    if (outDetail.getDeliveryQuantity() == 0.00) {
                        System.out.println("111111");
                    }
                    outSet.add(outDetail);
                    soDetailSet.add(soDetail);
                    break;
                } else {
                    //库存足够分配，全部填满SO的数量
                    soDetail.setDeliveryQuantity(soDetail.getOrderQuantity() - soDetail.getDeliveryQuantity());
                    soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_ALL_SEND);
                    BeanUtils.copyProperties(soDetail, outDetail);
                    outDetail.setBoxCode(allotInv.getBoxCode());
                    outDetail.setCellCode(allotInv.getCellCode());
                    outDetail.setBatchName(allotInv.getBatchName());
                    outDetail.setErpAreaId(allotInv.getErpAreaId());
                    outSet.add(outDetail);
                    set.add(soDetail);
                    soDetailSet.add(soDetail);

                    if (outDetail.getDeliveryQuantity() == 0.00) {
                        System.out.println("222222");
                    }

                    //扣减已分配的库存数量
                    invQty -= soQty;
                    //队列第一个元素被分配完毕，出队列
                    queue.poll();
                }
            }
        }
        soDetailService.updateBatchById(set);
        return outSet;

    }


    /**
     * 回传ERP
     *
     * @param
     * @param outBill
     */
//    public OrderToErpBO getErpBean(Set<OutDetail> outDetails, String outBill) {
//
//
//
//        Set<Integer> soDetailIds = outDetails.stream().map(OutDetail::getSoDetailId).collect(Collectors.toSet());
//        List<SoDetail> soDetails = soDetailService.listByIds(soDetailIds);
//        Map<Integer, List<SoDetail>> soDetailMap = soDetails.stream().collect(Collectors.groupingBy(SoDetail::getSoDetailId));
//        Set<String> billNo = soDetails.stream().map(SoDetail::getBillNo).collect(Collectors.toSet());
////        Set<String> billNo = soDetailMap.keySet();
//        List<SoMaster> soMasterList = soMasterService.list(new QueryWrapper<SoMaster>().in("bill_no", billNo));
//        Map<String, List<SoMaster>> soMasterSet = soMasterList.stream().collect(Collectors.groupingBy(SoMaster::getBillNo));
//        OrderToErpBO orderToErpBO = new OrderToErpBO();
//        //todo  生产任务单默认 88 24
//        orderToErpBO.setBillTypeId(24); //类型 88
//        orderToErpBO.setSourceBillTypeId(88); //
//        orderToErpBO.setRob(true); //红蓝字
//        orderToErpBO.setBillNo(outBill);//唯一单号
//        orderToErpBO.setBillDate(DateUtils.getNowDateString());//时间
//        List<OrderDetailBO> details = new ArrayList<>();
//        outDetails.forEach(item -> {
//            SoDetail sod = soDetailMap.get(item.getSoDetailId()).iterator().next();
//            OrderDetailBO orderDetailBO = new OrderDetailBO();
//            orderDetailBO.setSourceBillId(soMasterSet.get(sod.getBillNo()).iterator().next().getBeforeNum());//源单据id
//            orderDetailBO.setSourceBillDetailRowIndex(sod.getBomSplit());//行号
//            orderDetailBO.setAuxPropId(item.getPackDetailId());//辅助类型id
//            orderDetailBO.setBatchNo(sod.getDetailNo()); //批次
//            orderDetailBO.setQty(item.getDeliveryQuantity());//数量
//            orderDetailBO.setBatchNo(item.getBatchName()); //计划跟踪号
//            orderDetailBO.setStockId(item.getErpAreaId());
//            details.add(orderDetailBO);
//
//        });
//        orderToErpBO.setDetails(details);
//        return orderToErpBO;
//    }

    /**
     * 生成库存事务
     *
     * @param inventory   库存
     * @param currentUser 当前用户
     * @return 库存事务
     */
    public InventoryTransact toStockRequest(Inventory inventory, CurrentUser currentUser) {
        InventoryTransact inventoryTransact = new InventoryTransact();
        //Step1.准备数据
        //仓库
        inventoryTransact.setWareId(inventory.getWareId());
        inventoryTransact.setWareName(inventory.getWareName());
        //货主
        inventoryTransact.setToOrganizationId(inventory.getOrganizationId());
        inventoryTransact.setToOrganizationName(inventory.getOrganizationName());
        //库位
        inventoryTransact.setFromCellCode(inventory.getCellCode());
        //容器
        inventoryTransact.setFromBoxCode(inventory.getBoxCode());
        //物料
        inventoryTransact.setItemCode(inventory.getItemCode());
        inventoryTransact.setItemName(inventory.getItemName());
        inventoryTransact.setImgUrl(inventory.getImgUrl());
        //批次
        inventoryTransact.setFromBatchId(inventory.getBatchId());
        inventoryTransact.setFromBatchName(inventory.getBatchName());
        //数量
        inventoryTransact.setFromQuantity(inventory.getQuantity());
        //包装 转换率
        inventoryTransact.setFromPackDetailId(inventory.getPackDetailId());
        inventoryTransact.setFromPackDescribe(inventory.getPackDescribe());
        //创建人 时间
        inventoryTransact.setCreateUserId(currentUser.getUserId());
        inventoryTransact.setCreateUserName(currentUser.getUserName());
        inventoryTransact.setCreateTime(DateUtil.now());
        //事务类型
        inventoryTransact.setTransactType(InventoryConstant.INVENTORY_TYPE_OUT);
        //来源单据号
//        inventoryTransact.setBillNo(pickTask.getPickTaskCode());

        //Step2.保存，返回
        inventoryTransactService.save(inventoryTransact);
        return inventoryTransact;
    }


}
